package com.ruoyi.web.controller.system;

import cn.dev33.satoken.stp.StpUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SaTokenUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.file.domain.SysStorageConfig;
import com.ruoyi.file.domain.vo.UploadTokenVO;
import com.ruoyi.file.service.ISysStorageConfigService;
import com.ruoyi.file.service.storage.StorageService;
import com.ruoyi.file.service.storage.StorageServiceFactory;
import com.ruoyi.file.utils.FilePathUtils;
import com.ruoyi.file.utils.FileValidationUtils;
import com.ruoyi.file.utils.StorageConfigUtils;
import com.ruoyi.file.utils.ResponseUtils;
import com.ruoyi.file.utils.FileTypeUtils;
import com.ruoyi.file.utils.FileUrlUtils;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 个人信息 业务处理
 *
 * @author ruoyi
 */
@Slf4j
@Tag(name = "个人信息")
@RestController
@RequestMapping("/system/user/profile")
@RequiredArgsConstructor
public class SysProfileController extends BaseController {

    private final ISysUserService userService;
    private final ISysStorageConfigService storageConfigService;
    private final StorageServiceFactory storageServiceFactory;


    /**
     * 个人信息
     */
    @Operation(summary = "个人信息")
    @GetMapping
    public AjaxResult profile() {
        LoginUser loginUser = getLoginUser();
        SysUser user = loginUser.getUser();
        AjaxResult ajax = AjaxResult.success(user);
        ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
        ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
        return ajax;
    }

    /**
     * 修改用户
     */
    @Operation(summary = "修改用户")
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult updateProfile(@RequestBody SysUser user) {
        LoginUser loginUser = getLoginUser();
        SysUser currentUser = loginUser.getUser();
        currentUser.setNickName(user.getNickName());
        currentUser.setEmail(user.getEmail());
        currentUser.setPhonenumber(user.getPhonenumber());
        currentUser.setSex(user.getSex());
        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser)) {
            return error("修改用户'" + loginUser.getUsername() + "'失败，手机号码已存在");
        }
        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser)) {
            return error("修改用户'" + loginUser.getUsername() + "'失败，邮箱账号已存在");
        }
        if (userService.updateUserProfile(currentUser) > 0) {
            // 更新缓存用户信息
            // 更新用户会话中的用户信息
            StpUtil.getSession().set(Constants.LOGIN_USER_KEY, loginUser);
            return success();
        }
        return error("修改个人信息异常，请联系管理员");
    }

    /**
     * 重置密码
     */
    @Operation(summary = "重置密码")
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("/updatePwd")
    public AjaxResult updatePwd(@RequestBody Map<String, String> params) {
        String oldPassword = params.get("oldPassword");
        String newPassword = params.get("newPassword");
        LoginUser loginUser = getLoginUser();
        Long userId = loginUser.getUserId();
        String password = loginUser.getPassword();
        if (!SaTokenUtils.matchesPassword(oldPassword, password)) {
            return error("修改密码失败，旧密码错误");
        }
        if (SaTokenUtils.matchesPassword(newPassword, password)) {
            return error("新密码不能与旧密码相同");
        }
        newPassword = SaTokenUtils.encryptPassword(newPassword);
        if (userService.resetUserPwd(userId, newPassword) > 0) {
            // 更新缓存用户密码&密码最后更新时间
            loginUser.getUser().setPwdUpdateDate(DateUtils.getNowDate());
            loginUser.getUser().setPassword(newPassword);
            // 更新用户会话中的用户信息
            StpUtil.getSession().set(Constants.LOGIN_USER_KEY, loginUser);
            return success();
        }
        return error("修改密码异常，请联系管理员");
    }

    /**
     * 头像上传
     */
    @Operation(summary = "头像上传")
    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
    @PostMapping("/avatar")
    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) {
        try {
            if (file.isEmpty()) {
                return ResponseUtils.error("上传文件不能为空");
            }

            LoginUser loginUser = getLoginUser();
            String fileName = file.getOriginalFilename();

            // 获取并验证存储配置
            SysStorageConfig config = StorageConfigUtils.getAndValidateConfig(
                null, storageConfigService);

            // 验证文件大小
            String sizeError = FileValidationUtils.getFileSizeValidationError(
                file.getSize(), config.getMaxFileSize());
            if (sizeError != null) {
                return ResponseUtils.error(sizeError);
            }

            // 验证文件类型（头像只允许图片类型）
            if (StringUtils.isNotBlank(fileName)) {
                // 检查是否为图片文件
                if (!FileUrlUtils.isImageFile(fileName)) {
                    return ResponseUtils.error("只支持图片格式的文件");
                }

                // 如果配置了允许的文件类型，也要验证
                String fileTypeError = FileValidationUtils.getFileTypeValidationError(
                    fileName, config.getAllowedFileTypes());
                if (fileTypeError != null) {
                    return ResponseUtils.error(fileTypeError);
                }
            }

            // 使用存储服务上传文件到用户专属的avatar目录
            StorageService storageService = storageServiceFactory.getStorageService(config);
            String avatarPath = FileUrlUtils.buildAvatarPath(loginUser.getUserId());
            String filePath;
            try (InputStream inputStream = file.getInputStream()) {
                filePath = storageService.uploadFile(inputStream, fileName, file.getContentType(), config, avatarPath);
            }

            // 获取可访问的URL
            String fileUrl = storageService.getFileUrl(filePath, config);

            // 更新用户头像
            if (userService.updateUserAvatar(loginUser.getUserId(), fileUrl)) {
                // 删除旧头像文件（如果存在且不是默认头像）
                deleteOldAvatarFile(loginUser.getUser().getAvatar(), storageService, config);

                // 更新缓存用户头像
                loginUser.getUser().setAvatar(fileUrl);
                // 更新用户会话中的用户信息
                StpUtil.getSession().set(Constants.LOGIN_USER_KEY, loginUser);

                AjaxResult ajax = ResponseUtils.success("头像上传成功");
                ajax.put("imgUrl", fileUrl);
                ajax.put("filePath", filePath);

                log.info("用户头像上传成功: userId={}, fileName={}, url={}", 
                    loginUser.getUserId(), fileName, fileUrl);
                return ajax;
            } else {
                // 如果数据库更新失败，删除已上传的文件
                cleanupFailedUpload(filePath, storageService, config);
                return ResponseUtils.error("更新用户头像失败");
            }
        } catch (Exception e) {
            return ResponseUtils.handleException(e, "头像上传");
        }
    }

    /**
     * 删除旧头像文件
     *
     * @param oldAvatarUrl 旧头像URL
     * @param storageService 存储服务
     * @param config 存储配置
     */
    private void deleteOldAvatarFile(String oldAvatarUrl, StorageService storageService, SysStorageConfig config) {
        if (StringUtils.isEmpty(oldAvatarUrl) || FileUrlUtils.isDefaultAvatar(oldAvatarUrl)) {
            return; // 不删除默认头像
        }
        try {
            // 从URL中提取文件路径进行删除
            String oldFilePath = FileUrlUtils.extractFilePathFromUrl(oldAvatarUrl);
            if (StringUtils.isNotEmpty(oldFilePath)) {
                storageService.deleteFile(oldFilePath, config);
                log.info("删除旧头像文件成功: {}", oldFilePath);
            }
        } catch (Exception e) {
            log.warn("删除旧头像文件失败: {}", e.getMessage());
        }
    }

    /**
     * 清理上传失败的文件
     *
     * @param filePath 文件路径
     * @param storageService 存储服务
     * @param config 存储配置
     */
    private void cleanupFailedUpload(String filePath, StorageService storageService, SysStorageConfig config) {
        try {
            storageService.deleteFile(filePath, config);
            log.info("清理上传失败的文件成功: {}", filePath);
        } catch (Exception e) {
            log.warn("清理上传失败的文件异常: {}", e.getMessage());
        }
    }
}
